# $Id: devicebackup.py 7557b5d4d82b 2012/12/02 09:07:16 pgurumur $
# Copyright (c) 2009 Prabhu Gurumurthy  <pgurumur@gmail.com>
# 
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

import optparse
import os
import shutil
import socket
import sys

from django.conf import settings

from djanet.db import query
from djanet.compartment import models
from djanet.lib import exception, ip, scm, stdlib, log
from djanet.tools.lib import ConfigCopy, device, getopts

class Command(getopts.GetOptions):
   option_list = (
         optparse.make_option("-s", "--sleep", action = "store",
            dest = "sleep", type = "int", default = 180,
            help = "Seconds to sleep before processing backup"),
         optparse.make_option("-d", "--dir", action = "store",
            dest = "directory", type = "string", default = "/tftpboot",
            help = "TFTPboot backup directory"),
         optparse.make_option("-T", "--tftp", type = "str",
            help = "TFTP server used in case of static NAT", dest = "tftp"),
         ) + getopts.GetOptions.option_list
   
   help = "Backup device using SNMP/SSH"

   required_model_validation = False

   def __init__(self):
      super(Command, self).__init__()
      self.prog = __file__.split("/")[-1]
      self.tftp = None
      self.host = None
      self._svncfg = {}

   def GetTftp(self, server):
      if server is None:
         server = socket.gethostbyaddr(socket.gethostname())[-1][0]

      if server == "127.0.0.1":
         self.error("invalid TFTP server!")
      else:
         self.tftp = ip.ip(server)

   def GetScm(self, config):
      try:
         self.svn = scm.svn(username = config["USER"],
               password = config["PASS"])
         self.svn.Client()
      except scm.SCMError as err:
         self.error(err.message)

      revision = 0
      svndir = config["DIR"] + "/backups"

      try:
         shutil.rmtree(svndir)
      except OSError as err:
         pass

      if not os.path.exists(config["DIR"]):
         self.error("%s does not exists!", config["DIR"])

      if not os.path.isdir(config["DIR"]):
         self.error("%s is not a directory!", config["DIR"])

      try:
         os.chdir(settings.SVN_INFO)
         revision = self.svn.checkout(config["MOD"], config["HOST"])
      except scm.SCMError as err:
         self.error(err.message)

      try:
         os.stat(svndir)
      except OSError as err:
         self.error(err.message)

      if not revision:
         self.error("subversion checkout cannot be at revision zero")

      return revision

   def handle(self, *args, **options):
      try:
         self.host = args[1]
      except IndexError, message:
         pass

      if not hasattr(settings, 'SVN_INFO'):
         self.error("not SCM information provided!")

      self.log("SVN revison for %s: %d",
            settings.SVN_INFO["HOST"], self.GetScm(settings.SVN_INFO))
      self.GetTftp(options.get('tftp'))

      if self.host:
         hostip = None
         try:
            hostip = ip.ip(self.host)
            if hostip.size() > 1:
               self.error("Network defined instead of host, cannot do backups")
         except ip.IPError as err:
            self.error(err.message)

      sleep = 0
      try:
         sleep = int(options.get("sleep"))
      except ValueError as err:
         self.error(err.message)

      device = []
      if host:
         device.append(models.ConfigBackup.objects.filter(
            device__exact = query.GetDevice(host)))
      else:
         device = models.ConfigBackup.objects.all()


      # --- Need to continue after this..

      backupObject = models.ConfigBackup.objects.filter(
            device__exact = device.id)
      cmptLocation = models.DeviceLocations.objects.filter(
            device__exact = device.id).values('compartment')[0]
      if cmptLocation:

         compartment = models.CompartmentInfo.objects.filter(id__exact =
               backupObject["compartment"]).values('snmp_write')[0]
         if backupObject["ssh"] != 0:
            ssh = models.SSHCredentials.objects.filter(id__exact =
                  backupObject['ssh']).values()[0]
         if comparment["active"]:
            snmp = compartment["snmp_write"]

         backup = device.DeviceBackup(community = snmp,
               tftp = tftp, device = device, sleep = sleep)
         backup.start()
         backup.join()
      else:
         if os.path.isdir(options.get("directory")):
            try:
               svn = scm.svn(username = settings.SCMUSER, pasword =
                     settings.SCMPASSWD)
            except scm.SCMError, message:
               raise CommandError, message

         backupObjects = models.ConfigBackup.objects.values()
         backupList = []
         for attrs in backupObjects:
            if attrs["active"]:
               snmp = None
               device = query.GetDeviceIPAddress(int(attrs['device']))
               compartment = models.CompartmentInfo.objects.filter(
                     id__exact = int(attr["compartment"])).values()[0]
               if compartment["active"]:
                  snmp = compartment["snmp_write"]

               if device and snmp:
                  backup = device.DeviceBackup(community = snmp,
                        tftp = tftp, device = device, sleep = sleep)
               backupList.append(backup)
               backup.start()

         for objects in backupList:
            objects.join()
